package com.cnfangmao.masterdata.storage;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.bson.conversions.Bson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import com.cnfangmao.masterdata.common.util.GenericsUtils;
import com.cnfangmao.masterdata.dto.PageDto;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;

/**
 * @description: 主数据持久化层（mongodb）
 * @author: chenxc
 * @date: 2020年4月21日 上午10:21:47
 */
@Service
public class BasicDataStorageServiceWithMongodb<T> {

	@Autowired
	private MongoTemplate mongoTemplate;

	/**
	 * @description: 新增一条主数据
	 * @author: chenxc
	 * @date: 2020年4月21日 下午4:20:08
	 * @param entity
	 * @param collectionName
	 * @return
	 * @see com.cnfangmao.masterdata.storage.BasicDataStorageService#insert(java.lang.Object,
	 *      java.lang.String)
	 */
	public boolean insert(T entity, String collectionName) {
		return this.mongoTemplate.insert(entity, collectionName) != null;
	}

	/**
	 * @description: 批量新增主数据
	 * @author: chenxc
	 * @date: 2020年4月21日 下午4:20:08
	 * @param entityList
	 * @param collectionName
	 * @return
	 * @see com.cnfangmao.masterdata.storage.BasicDataStorageService#insertBatch(java.util.Collection,
	 *      java.lang.String)
	 */
	public boolean insertBatch(Collection<T> entityList, String collectionName) {
		return this.mongoTemplate.insert(entityList, collectionName) != null;
	}

	/**
	 * @description: 更新主数据
	 * @author: chenxc
	 * @date: 2020年4月21日 下午4:20:08
	 * @param entity
	 * @param collectionName
	 * @param queryColumnMap
	 * @return
	 * @see com.cnfangmao.masterdata.storage.BasicDataStorageService#updateByMap(java.lang.Object,
	 *      java.lang.String, java.util.Map)
	 */
	public boolean updateByMap(T entity, String collectionName, Map<String, Object> queryColumnMap) {
		// 构造查询条件
		Query query = BasicDataStorageServiceWithMongodb.getAndQuery(queryColumnMap);
		return this.update(entity, collectionName, query);
	}
	
	public boolean update(T entity, String collectionName, Query query){
		// 将对象转成Bson
		DBObject dbDoc = new BasicDBObject();
		this.mongoTemplate.getConverter().write(entity, (Bson) dbDoc);

		// 构造待更新的字段
		Update update = new Update();
		for (String key : dbDoc.keySet()) {
			if (key.equalsIgnoreCase("_class")) {
				continue;
			}
			Object value = dbDoc.get(key);
			update.set(key, value);
		}

		UpdateResult result = this.mongoTemplate.updateMulti(query, update, collectionName);

		return result.getModifiedCount() > 0;
	}

	/**
	 * @description: TODO
	 * @author: chenxc
	 * @date: 2020年4月21日 下午4:20:08
	 * @param collectionName
	 * @param queryColumnMap
	 * @return
	 * @see com.cnfangmao.masterdata.storage.BasicDataStorageService#deleteByMap(java.lang.String,
	 *      java.util.Map)
	 */
	public boolean deleteByMap(String collectionName, Map<String, Object> queryColumnMap) {
		// 构造查询条件
		Query query = BasicDataStorageServiceWithMongodb.getAndQuery(queryColumnMap);
		
		return this.delete(collectionName, query);
	}
	
	public boolean delete(String collectionName, Query query){
		DeleteResult result = this.mongoTemplate.remove(query, collectionName);
		return result.getDeletedCount() > 0;
	}

	/**
	 * @description: 查询主数据
	 * @author: chenxc
	 * @date: 2020年4月21日 下午7:23:12
	 * @param entityClass
	 * @param collectionName
	 * @param queryColumnMap
	 * @return
	 * @see com.cnfangmao.masterdata.storage.BasicDataStorageService#selectByMap(java.lang.Class,
	 *      java.lang.String, java.util.Map)
	 */
	public List<T> findByMap(String collectionName, Map<String, Object> queryColumnMap) {
		// 构造查询条件
		Query query = BasicDataStorageServiceWithMongodb.getAndQuery(queryColumnMap);

		return this.find(collectionName, query);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> find(String collectionName, Query query){
		Class<?> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());
		
		return (List<T>) this.mongoTemplate.find(query, entityClass, collectionName);
	}
	
	/**
	 * @description: 分页根据Map对象的条件进行模糊与查询 
	 * @author: chenxc
	 * @date: 2020年4月22日 下午5:48:27
	 * @param: @param collectionName
	 * @param: @param page
	 * @param: @param queryColumnMap
	 * @param: @return      
	 * @return: List<T>      
	 * @throws
	 */
	public List<T> findPageByMap(String collectionName, PageDto page, Map<String, Object> queryColumnMap) {
		// 构造查询条件
		Query query = BasicDataStorageServiceWithMongodb.getAndQuery(queryColumnMap);
		return this.findPage(collectionName, page, query);
	}
	
	/**
	 * @description: 外部构造Query对象进行查询 
	 * @author: chenxc
	 * @date: 2020年4月23日 下午2:26:19
	 * @param: @param collectionName
	 * @param: @param page
	 * @param: @param query
	 * @param: @return      
	 * @return: List<T>      
	 * @throws
	 */
	@SuppressWarnings("unchecked")
	public List<T> findPage(String collectionName, PageDto page, Query query){
		query = query.skip((page.getIndex() - 1) * page.getSize()).limit(page.getSize());

		Class<?> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());
		
		return (List<T>) this.mongoTemplate.find(query, entityClass, collectionName);
	}
	

	/**
	 * @description: 分页根据Map对象的条件进行统计行数
	 * @author: chenxc
	 * @date: 2020年4月22日 下午5:48:05
	 * @param: @param collectionName
	 * @param: @param page
	 * @param: @param queryColumnMap
	 * @param: @return      
	 * @return: Long      
	 * @throws
	 */
	public Long findCountByMap(String collectionName, Map<String, Object> queryColumnMap) {
		// 构造查询条件
		Query query = BasicDataStorageServiceWithMongodb.getAndQuery(queryColumnMap);
		return this.findCount(collectionName, query);
	}
	
	public Long findCount(String collectionName, Query query){
		return this.mongoTemplate.count(query, collectionName);
	}

	
	/**
	 * @description: 构造与的模糊查询的过滤条件Query
	 * @author: chenxc
	 * @date: 2020年4月23日 下午3:44:48
	 * @param filterColumnMap
	 * @return      
	 * Query      
	 * @throws
	 */
	public static Query getAndQuery(Map<String, Object> filterColumnMap) {
		Query query = new Query();
		if(filterColumnMap == null || filterColumnMap.size() == 0){
			return query;
		}
		
		for (Map.Entry<String, Object> item : filterColumnMap.entrySet()) {
			String value = (String) item.getValue();
			// 不区分大小写
			Pattern pattern = Pattern.compile(String.format("^.*" + value + ".*$"), Pattern.CASE_INSENSITIVE);

			query.addCriteria(Criteria.where(item.getKey()).regex(pattern));
		}

		return query;
	}
}
